package com.wh.hotel.service.strategy;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.json.JSONUtil;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.wh.hotel.enums.strategy.PriceGapTypeEnum;
import com.wh.hotel.enums.strategy.SuitTypeEnum;
import com.wh.hotel.enums.strategy.TimeTypeEnum;
import com.wh.hotel.param.HotelQueryRoomParam;
import com.wh.hotel.po.PriceChangeVo;
import com.wh.hotel.service.strategy.price.PriceCalculatorTemplate;
import com.wh.hotel.service.strategy.room.SuitRangeTemplate;
import com.wh.hotel.service.strategy.time.ValidTimeTemplate;
import com.wh.hotel.vo.HotelPriceStrategyVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * @author wenhao
 */
@Slf4j
@Component
public class PriceStrategyFactory {

    private static final Map<SuitTypeEnum, SuitRangeTemplate> SUIT_RANGE_TEMPLATE_MAP = Maps.newHashMap();
    private static final Map<TimeTypeEnum, ValidTimeTemplate> VALID_TIME_TEMPLATE_MAP = Maps.newHashMap();
    private static final Map<PriceGapTypeEnum, PriceCalculatorTemplate> PRICE_CALCUATOR_TEMPLATE_MAP = Maps.newHashMap();

    @Resource
    private SuitRangeTemplate roomTypeSuitRange;

    @Resource
    private ValidTimeTemplate absoluteValidTime;
    @Resource
    private ValidTimeTemplate foreverValidTime;
    @Resource
    private ValidTimeTemplate preWeekValidTime;

    @Resource
    private PriceCalculatorTemplate absolutePriceCalculator;
    @Resource
    private PriceCalculatorTemplate percentPriceCalculator;

    @PostConstruct
    public void init() {
        SUIT_RANGE_TEMPLATE_MAP.put(SuitTypeEnum.HOTEL_ROOM, roomTypeSuitRange);

        VALID_TIME_TEMPLATE_MAP.put(TimeTypeEnum.ABSOLUTE_TIME, absoluteValidTime);
        VALID_TIME_TEMPLATE_MAP.put(TimeTypeEnum.PRE_WEEK, preWeekValidTime);
        VALID_TIME_TEMPLATE_MAP.put(TimeTypeEnum.FOREVER, foreverValidTime);

        PRICE_CALCUATOR_TEMPLATE_MAP.put(PriceGapTypeEnum.PERCENT, percentPriceCalculator);
        PRICE_CALCUATOR_TEMPLATE_MAP.put(PriceGapTypeEnum.ABSOLUTE, absolutePriceCalculator);
    }

    public SuitRangeTemplate getSuitRangeTemplate(SuitTypeEnum suitTypeEnum) {
        return SUIT_RANGE_TEMPLATE_MAP.get(suitTypeEnum);
    }

    public ValidTimeTemplate getValidTimeTemplate(TimeTypeEnum timeTypeEnum) {
        return VALID_TIME_TEMPLATE_MAP.get(timeTypeEnum);
    }

    public PriceCalculatorTemplate getPriceCalculatorTemplate(PriceGapTypeEnum priceGapTypeEnum) {
        return PRICE_CALCUATOR_TEMPLATE_MAP.get(priceGapTypeEnum);
    }

    public List<HotelPriceStrategyVo> filterBySuitRange(List<HotelPriceStrategyVo> orgStrategyList, HotelQueryRoomParam param) {
        List<HotelPriceStrategyVo> result = Lists.newArrayListWithCapacity(CollUtil.size(orgStrategyList));
        for (HotelPriceStrategyVo strategyVo : orgStrategyList) {
            SuitTypeEnum suitTypeEnum = SuitTypeEnum.parse(strategyVo.getSuitRangePo().getSuitRangeType());
            SuitRangeTemplate suitRangeTemplate = getSuitRangeTemplate(suitTypeEnum);
            if (suitRangeTemplate == null) {
                log.warn("存在脏数据 data={}", JSONUtil.toJsonStr(strategyVo));
                continue;
            }
            if (suitRangeTemplate.isHit(param, strategyVo)) {
                result.add(strategyVo);
            }
        }
        return result;
    }

    public List<HotelPriceStrategyVo> filterByTimeType(List<HotelPriceStrategyVo> orgStrategyList, Date cur) {
        List<HotelPriceStrategyVo> result = Lists.newArrayListWithCapacity(CollUtil.size(orgStrategyList));
        for (HotelPriceStrategyVo strategyVo : orgStrategyList) {
            TimeTypeEnum timeTypeEnum = TimeTypeEnum.parse(strategyVo.getValidTimePo().getTimeType());
            ValidTimeTemplate validTimeTemplate = getValidTimeTemplate(timeTypeEnum);
            if (validTimeTemplate == null) {
                log.warn("存在脏数据 data={}", JSONUtil.toJsonStr(strategyVo));
                continue;
            }
            if (validTimeTemplate.isHit(cur, strategyVo)) {
                result.add(strategyVo);
            }
        }
        return result;
    }

    public Integer calculateOrgPrice(Integer basePrice, HotelPriceStrategyVo strategyVo) {
        PriceChangeVo priceChangeVo = strategyVo.getPriceChangeVo();
        PriceGapTypeEnum priceGapTypeEnum = PriceGapTypeEnum.parse(priceChangeVo.getPriceGapType());
        PriceCalculatorTemplate priceCalculatorTemplate = getPriceCalculatorTemplate(priceGapTypeEnum);
        if (priceGapTypeEnum == null) {
            log.error("找不到价格计算末班 data={}", JSONUtil.toJsonStr(strategyVo));
            return -1;
        }
        return priceCalculatorTemplate.calculateBasePrice(basePrice, strategyVo);
    }
}
